﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Minio;
using Minio.ApiEndpoints;
using Minio.DataModel.Args;
using Minio.DataModel.Result;
using Minio.Exceptions;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Reactive.Linq;

namespace B.S.BaseData.Read.Api.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class FileUploadController : ControllerBase
    {
        private readonly IMinioClient minioClient;
        private string bucketName = "one";

        public FileUploadController()
        {
            minioClient = new MinioClient()
                .WithEndpoint("10.223.8.3:9000")
                .WithCredentials("admin", "admin123")
                .WithSSL(false)
                .Build();
        }

        /// <summary>
        /// 列出所有桶
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> ListBuckets()
        {
            ListAllMyBucketsResult buckets = await minioClient.ListBucketsAsync().ConfigureAwait(false);
            return Ok(buckets);
        }

        /// <summary>
        /// 上传单个文件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            //检查桶是否存在
            BucketExistsArgs? beArgs = new BucketExistsArgs()
                .WithBucket(bucketName);

            bool fount = await minioClient.BucketExistsAsync(beArgs);

            if (!fount)
            {
                //MakeBucketArgs 是用于配置穿件存储桶操作的参数对象
                MakeBucketArgs? mbArgs = new MakeBucketArgs().WithBucket(bucketName);
                await minioClient.MakeBucketAsync(mbArgs).ConfigureAwait(false);
            }

            //获取文件名
            string? objectName = file.FileName;

            //使用流数据上传文件
            //注意：MINIO API 要求 Content-Type 和 ObjectSize参数
            PutObjectArgs? putArgs = new PutObjectArgs()
                .WithBucket(bucketName)
                .WithObject(objectName)
                .WithStreamData(file.OpenReadStream())
                .WithContentType(file.ContentType)
                .WithObjectSize(file.Length);
            await minioClient.PutObjectAsync(putArgs).ConfigureAwait(false);

            //在服务器端生成一个预签名
            //客户端可以使用该URL来直接下载MinIO存储中的特定对象
            //并将其作为JSON格式的响应数据返回给客户端
            PresignedGetObjectArgs getArgs = new PresignedGetObjectArgs()
                .WithBucket(bucketName)
                .WithObject(objectName)
                .WithExpiry(7200);
            string? url = await minioClient.PresignedGetObjectAsync(getArgs).ConfigureAwait(false);
            return Ok(JsonConvert.SerializeObject(url));
        }

        /// <summary>
        /// 查询 one 桶中的数据
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> ListObjectsInOneBucket()
        {
            try
            {
                var listObjectsArgs = new ListObjectsArgs()
                   .WithBucket(bucketName);

                var objects = minioClient.ListObjectsAsync(listObjectsArgs);

                var objectList = new List<Minio.DataModel.Item>();
                foreach (var obj in objects)
                {
                    objectList.Add(obj);
                }

                return Ok(objectList);
            }
            catch (MinioException minioEx)
            {
                Debug.WriteLine($"MinIO error listing objects: {minioEx.Message}");
                return StatusCode(500, $"MinIO error while listing objects in the bucket: {minioEx.Message}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"General error listing objects: {ex.Message}");
                return StatusCode(500, $"An error occurred while listing objects in the bucket: {ex.Message}");
            }
        }

        /// <summary>
        /// 删除 one 桶中的指定对象
        /// </summary>
        /// <param name="objectName">对象名称</param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<IActionResult> DeleteObjectInOneBucket(string objectName)
        {
            try
            {
                var removeObjectArgs = new RemoveObjectArgs()
                   .WithBucket(bucketName)
                   .WithObject(objectName);

                await minioClient.RemoveObjectAsync(removeObjectArgs);
                return Ok($"Object {objectName} in bucket {bucketName} has been deleted.");
            }
            catch (MinioException minioEx)
            {
                Debug.WriteLine($"MinIO error deleting object: {minioEx.Message}");
                return StatusCode(500, $"MinIO error while deleting object {objectName} in the bucket: {minioEx.Message}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"General error deleting object: {ex.Message}");
                return StatusCode(500, $"An error occurred while deleting object {objectName} in the bucket: {ex.Message}");
            }
        }

        /// <summary>
        /// 查看 one 桶中指定对象的信息
        /// </summary>
        /// <param name="objectName">对象名称</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetObjectInfoInOneBucket(string objectName)
        {
            try
            {
                var statObjectArgs = new StatObjectArgs()
                   .WithBucket(bucketName)
                   .WithObject(objectName);

                var objectStat = await minioClient.StatObjectAsync(statObjectArgs);
                return Ok(objectStat);
            }
            catch (MinioException minioEx)
            {
                Debug.WriteLine($"MinIO error getting object info: {minioEx.Message}");
                return StatusCode(500, $"MinIO error while getting info of object {objectName} in the bucket: {minioEx.Message}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"General error getting object info: {ex.Message}");
                return StatusCode(500, $"An error occurred while getting info of object {objectName} in the bucket: {ex.Message}");
            }
        }

        /// <summary>
        /// 下载 one 桶中的指定文件
        /// </summary>
        /// <param name="objectName">对象名称</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> DownloadObjectInOneBucket(string objectName)
        {
            try
            {
                var getObjectArgs = new GetObjectArgs()
                   .WithBucket(bucketName)
                   .WithObject(objectName);

                var memoryStream = new MemoryStream();
                // 定义回调函数来处理流数据
                Action<Stream> callback = (stream) =>
                {
                    stream.CopyTo(memoryStream);
                };
                getObjectArgs.WithCallbackStream(callback);

                await minioClient.GetObjectAsync(getObjectArgs);
                memoryStream.Position = 0;
                return File(memoryStream, "application/octet-stream", objectName);
            }
            catch (MinioException minioEx)
            {
                Debug.WriteLine($"MinIO error downloading object: {minioEx.Message}");
                return StatusCode(500, $"MinIO error while downloading object {objectName} from the bucket: {minioEx.Message}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"General error downloading object: {ex.Message}");
                return StatusCode(500, $"An error occurred while downloading object {objectName} from the bucket: {ex.Message}");
            }
            finally
            {
                // 可以在这里添加逻辑来手动关闭流，不过ASP.NET Core会在响应完成后自动处理
            }
        }
    }
}
